from django.db import models
from django.contrib.auth.models import User
from .protocol import HttpApiModel, ThriftApiModel, SqlApiModel


class CaseModel(models.Model):
    product = models.ForeignKey(
        "products.Products",
        on_delete=models.SET_NULL,
        null=True,
    )
    name = models.CharField(max_length=255, verbose_name="测试用例名称", db_index=True)

    host = models.URLField(
        verbose_name="域名", null=True, blank=True, help_text="全局基础URL"
    )
    port = models.IntegerField(
        verbose_name="端口", null=True, blank=True, help_text="全局基础URL所需端口"
    )
    variables = models.JSONField(
        verbose_name="全局变量", help_text="全局变量，作用域覆盖整个测试用例", null=True, blank=True
    )
    parameters = models.JSONField(
        verbose_name="数据驱动测试", help_text="实现数据驱动测试，支持CSV/函数参数化", null=True, blank=True
    )
    export = models.JSONField(
        verbose_name="导出会话变量", help_text="导出会话变量供其他测试用例调用", null=True, blank=True
    )
    report = models.FileField(
        upload_to="cases/reports/",
        verbose_name="测试报告",
        help_text="测试报告路径",
        null=True,
        blank=True,
    )
    owner = models.ForeignKey(
        User,
        verbose_name="归属人",
        related_name="case_owner",
        on_delete=models.SET_NULL,
        null=True,
    )
    status = models.BooleanField(default=False, verbose_name="调试否通过")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")

    class Meta:
        db_table = "cool_test_cases"
        verbose_name = "测试用例"
        verbose_name_plural = "测试用例"


class CaseStep(models.Model):
    case = models.ForeignKey(
        CaseModel, on_delete=models.CASCADE, related_name="cases_step"
    )
    name = models.CharField(max_length=255, verbose_name="步骤名称", db_index=True)
    step = models.IntegerField(verbose_name="步骤序号", db_index=True)
    http_api = models.OneToOneField(
        HttpApiModel,
        on_delete=models.CASCADE,
        verbose_name="HTTP API",
        help_text="HTTP 协议接口",
        blank=True,
        null=True,
    )
    test_case = models.OneToOneField(
        CaseModel,
        on_delete=models.CASCADE,
        verbose_name="用例步骤",
        help_text="引用其他测试用例或函数，支持用例复用",
    )

    variables = models.JSONField(
        verbose_name="步骤变量",
        help_text="步骤变量，作用域仅在本步骤内; 优先级高于全局变量,若与Config中变量同名，优先使用步骤变量",
        null=True,
        blank=True,
    )
    setup_hooks = models.JSONField(
        verbose_name="前置操作", help_text="在请求发送前执行的钩子函数，用于预处理请求参数", null=True, blank=True
    )
    teardown_hooks = models.JSONField(
        verbose_name="后置操作",
        help_text="在请求完成后执行的钩子函数，用于修改响应或清理数据。",
        null=True,
        blank=True,
    )
    extract = models.JSONField(
        verbose_name="提取数据",
        help_text="使用JMESPath或正则表达式从响应中提取数据。",
        null=True,
        blank=True,
    )
    export = models.JSONField(
        verbose_name="导出会话变量", help_text="导出会话变量供其他测试用例或步骤使用", null=True, blank=True
    )
    validators = models.JSONField(
        verbose_name="验证器", help_text="结果校验器，支持内置断言和自定义函数", null=True, blank=True
    )
    validate_script = models.JSONField(
        verbose_name="验证器脚本",
        help_text='在步骤执行后执行的验证器脚本，返回 True/False 作为验证结果,{"name":"path"}',
        null=True,
        blank=True,
    )
    retry_times = models.SmallIntegerField(
        verbose_name="重试次数", default=0, help_text="在失败时重试的次数"
    )
    retry_interval = models.IntegerField(
        verbose_name="重试间隔", default=0, help_text="重试的间隔，单位为秒"
    )
    thrift_api = models.OneToOneField(
        ThriftApiModel,
        on_delete=models.CASCADE,
        verbose_name=" Thrift 请求",
        help_text=" Thrift 协议请求",
        blank=True,
        null=True,
    )
    sql_api = models.OneToOneField(
        SqlApiModel,
        on_delete=models.CASCADE,
        verbose_name="SQL 请求",
        help_text="SQL 协议请求",
        blank=True,
        null=True,
    )

    class Meta:
        db_table = "cool_test_case_steps"
        verbose_name = "测试步骤"
        verbose_name_plural = "测试步骤"

    def __str__(self):
        return self.name
